#include "nr_device_item.h"

nr_device_item::nr_device_item()
    : m_parent_item(NULL)
    , m_device_type(NULL)
    , m_device(NULL)
{
}

nr_device_item::nr_device_item(nr_device_item& item)
    : m_parent_item(NULL)
    , m_device_type(NULL)
    , m_device(NULL)
{
    copy_data(item);
}

nr_device_item::~nr_device_item()
{
}

nr_device_item& nr_device_item::operator = (nr_device_item &item)
{
    // Copy it 
    copy_data(item);

    return *this;
}

void nr_device_item::copy_data(nr_device_item& item)
{
    this->id() = item.id();
    this->name() = item.name();

    // Copy each property
    for(nr_device_property_hash::iterator it = item.properties().begin();
        it != item.properties().end(); ++it)
    {
        nr_device_property* prop = new nr_device_property(*it.value());
        this->properties().insert(it.key(), prop);
    }

    // Copy sub-items
    for(nr_device_item_hash::iterator it = item.items().begin();
        it != item.items().end(); ++it)
    {
        nr_device_item *new_item = new nr_device_item(*it.value());
        this->items().insert(it.key(), new_item);
    }
}

nr_device_item* nr_device_item::find_device_item_by_id(const nr_device_id_t &device_id)
{
    // Compare itself 
    if (device_id == m_id)
        return this;

    // Find in the sub-item
    foreach(nr_device_item* sub_item, this->items())
    {
        nr_device_item* item = sub_item->find_device_item_by_id(device_id);
        if (item != NULL)
            return item;
    }
    
    // Not found
    return NULL;
}

void nr_device_item::serialize(QDataStream& data_stream)
{
    // Save each field
    data_stream << this->id();
    data_stream << this->name();
    
    // Save the property count
    // Save properties
    data_stream << this->properties().count();
    for(nr_device_property_hash::iterator it = this->properties().begin();
        it != this->properties().end(); ++it)
    {
        data_stream << it.key();
        nr_device_property* child_prop = it.value();
        child_prop->serialize(data_stream);
    }
    
    // Save the sub-item count
    // Save sub-items
    data_stream << this->items().count();
    for(nr_device_item_hash::iterator it = this->items().begin();
        it != this->items().end(); ++it)
    {
        data_stream << it.key();
        nr_device_item* child_item = it.value();
        child_item->serialize(data_stream);
    }
    
    nr_object::serialize(data_stream);
}

void nr_device_item::deserialize(QDataStream& data_stream)
{
    // Get each field
    data_stream >> this->id();
    data_stream >> this->name();
    
    // Get the properties
    int child_count = 0;
    data_stream >> child_count;
    for(int i = 0; i < child_count; ++i)
    {
        nr_id_t id;
        nr_device_property* prop = new nr_device_property;
        
        data_stream >> id;
        prop->deserialize(data_stream);
        this->properties().insert(id, prop);
    }
    
    // Get the sub-items
    child_count = 0;
    data_stream >> child_count;
    for(int i = 0; i < child_count; ++i)
    {
        nr_device_id_t id;
        nr_device_item* item = new nr_device_item;
        
        data_stream >> id;
        item->deserialize(data_stream);
        this->items().insert(id, item);
    }
    
    nr_object::deserialize(data_stream);
}

nr_error_t nr_device_item::init_device()
{
    nr_error_t status = NR_ERROR_NONE;
    
    // Try to init its parent first
    if (m_parent_item != NULL)
    {
        // Init the parent device
        status = m_parent_item->init_device();
        if (NR_FAILED(status))
            return status;        
        
        Q_ASSERT(m_parent_item->device());
    }
    
    // Create the device object and attach the device item
    Q_ASSERT(m_device_type);
    this->device() = m_device_type->create_device();
    Q_ASSERT(this->device());
    this->device()->device_item() = this;
    
    // Set the parent and child if parent is not null
    if (m_parent_item != NULL)
    {
        m_parent_item->device()->add_child_device(this->device());
    }

    return NR_ERROR_NONE;
}


